package com.kanbox.api;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.R.raw;
import android.accounts.NetworkErrorException;
import android.util.Log;

public class KanboxServer {
    private HttpRequestBase mHttpRequest;
    private RequestListener mRequestListener;
    private KanboxException mException;
    private int mOpType;
    private String mDestPath;
    private UploadFileStatus mUpLoadFileListener;
    private DownloadFileStatus mDownLoadFileListener;
    private ExecutorService mExecutorService;
    private static final String TAG = "FileListKanboxServer";
    /**
     * @param destPath
     *
     * @param httpRequest
     * @param listener
     * @param opType
     */

    private static KanboxServer mkanboxServer;

    private KanboxServer() {
        mExecutorService = Executors.newFixedThreadPool(20);
    }

    public static KanboxServer getInstance() {
        if (mkanboxServer == null) {
            mkanboxServer = new KanboxServer();
        }
        return mkanboxServer;
    }

    protected void executeTask(Runnable runnable) {
        mExecutorService.execute(runnable);
    }
    public void disconnectKanboxService(){
        Log.d(TAG,"disconnect kanbox network----------------------------------");
        executeTask(new Runnable() {
          //BugID:101951:fix cancel bug when showing progress dialog
            @Override
            public void run() {
                try {
                    mHttpRequest.abort();
                } catch (Exception e) {
                    Log.e(TAG,"disconnect kanbox service excepiton");
                    e.printStackTrace();
                }
            }
        });
      

    }
    public void doHttp(HttpRequestBase httpRequest, RequestListener listener,
            int opType) {
        mHttpRequest = httpRequest;
        mRequestListener = listener;
        mOpType = opType;

        executeTask(new Runnable() {
            HttpClient sHttpClient = createHttpClient();
            String result = "";

            @Override
            public void run() {
                try {
                    if(mHttpRequest.isAborted()){
                        Log.d(TAG,"mHttpRequest isAborted return ");
                        return;
                    }
                    HttpResponse sHttpResponse = sHttpClient
                            .execute(mHttpRequest);
                    int statusCode = sHttpResponse.getStatusLine()
                            .getStatusCode();
                    Log.d(TAG,"dohttp respose code is "+statusCode);
                    if (statusCode == 200) {
                        String strResult = EntityUtils.toString(sHttpResponse
                                .getEntity());
                        result = strResult;
                        Log.d(TAG,"result is "+result);
                    } else {
                        mException = new KanboxException(statusCode);
                        result = "error";
                    }
                } catch (ClientProtocolException e) {
                    mException = new KanboxException(e);
                    result = "error";
                } catch (IOException e) {
                    mException = new KanboxException(e);
                    //BugID:109775:fix bug when disconnect http
                    result = "ioerror";
                }finally {
                    if (result == null || result.equals("error")) {
                        mRequestListener.onError(mException, mOpType);
                    } else {
                        mRequestListener.onComplete(result, mOpType);
                    }
                }
            }
        });
    }

    public void upload(String destPath, HttpRequestBase httpRequest,
            UploadFileStatus listener, int opType) {
        mDestPath = destPath;
        mHttpRequest = httpRequest;
        mUpLoadFileListener = listener;
        mOpType = opType;

        executeTask(new Runnable() {
            HttpClient sHttpClient = createHttpClient();
            String result = "";

            @Override
            public void run() {
                try {
                    if(mHttpRequest.isAborted()){
                        Log.d(TAG,"mHttpRequest isAborted return ");
                        return;
                    }
                    HttpResponse sHttpResponse = sHttpClient
                            .execute(mHttpRequest);
                    int statusCode = sHttpResponse.getStatusLine()
                            .getStatusCode();
                    if (statusCode == 200) {
                        String strResult = EntityUtils.toString(sHttpResponse
                                .getEntity());
                        result = strResult;
                    } else {
                        mException = new KanboxException(statusCode);
                        result = "error";
                        Log.e(TAG,"upload error respose code is "+statusCode+",excepiton is "+mException);
                    }
                } catch (ClientProtocolException e) {
                    mException = new KanboxException(e);
                    result = "error";
                    Log.e(TAG,"upload error ClientProtocolException excepiton is "+mException);
                } catch (IOException e) {
                    mException = new KanboxException(e);
                    //BugID:109775:fix bug when disconnect http
                    result = "ioerror";
                    Log.e(TAG,"upload error IOException excepiton is "+mException);
                } finally {
                    if (result == null || result.equals("error")) {
                        mUpLoadFileListener.onError(mException, mOpType);
                        Log.e(TAG,"upload final error ,result is "+result);
                    } else {
                        mUpLoadFileListener.onComplete(result, mOpType);
                        Log.e(TAG,"upload final  complete result is "+result);
                    }
                }
            }
        });
    }

    public void download(String destPath, HttpRequestBase httpRequest,
            DownloadFileStatus listener, int opType) {
        mDestPath = destPath;
        mHttpRequest = httpRequest;
        mDownLoadFileListener = listener;
        mOpType = opType;

        executeTask(new Runnable() {
            HttpClient sHttpClient = createHttpClient();
            String result = "";

            @Override
            public void run() {
                try {
                    if(mHttpRequest.isAborted()){
                        Log.d(TAG,"mHttpRequest isAborted return ");
                        return;
                    }
                    HttpResponse sHttpResponse = sHttpClient
                            .execute(mHttpRequest);
                    int statusCode = sHttpResponse.getStatusLine()
                            .getStatusCode();
                    if (statusCode == 200) {
                        result = downloading(sHttpResponse.getEntity());
                        Log.d(TAG,"progress download result is "+result);
                    } else {
                        mException = new KanboxException(statusCode);
                        result = "error";
                        Log.e(TAG,"progress download result is error,exception is "+mException);
                    }
                } catch (ClientProtocolException e) {
                    mException = new KanboxException(e);
                    result = "error";
                    Log.e(TAG,"progress download result is error,ClientProtocolException exception is "+mException);
                    e.printStackTrace();
                } catch (IOException e) {
                    mException = new KanboxException(e);
                    //BugID:109775:fix bug when disconnect http
                    result = "ioerror";
                    Log.e(TAG,"progress download result is error,IOException exception is "+mException);
                    e.printStackTrace();
                } finally {
                    if (result == null || result.equals("error")) {
                        mDownLoadFileListener.onError(mException, mOpType);
                        Log.e(TAG,"progress finally download onError ,result is "+result);
                    } else {
                        mDownLoadFileListener.onComplete(result, mOpType);
                        Log.e(TAG,"progress finally download onComplete result is "+result);
                    }
                }
            }
        });
    }

    /**
     * 读取数据流，并写到本地
     *
     * @param entity
     * @return
     */
    private String downloading(HttpEntity entity) {
        try {
            int size = 10 * 1024;
            InputStream is = entity.getContent();
            FileOutputStream fos = new FileOutputStream(mDestPath);
            //Log.d(TAG,"progress downloading write file mDestPath is "+mDestPath);
            byte[] buf = new byte[size];
            int num = -1;
            long count = 0, sendMessageNextPos = 0;
            mDownLoadFileListener.onStart(Constant.OP_DOWNLOAD);
            if (is != null) {
                while ((num = is.read(buf)) != -1) {
                    fos.write(buf, 0, num);
                    count += num;
                    if (count > sendMessageNextPos) {
                        sendMessageNextPos += size;
                        mDownLoadFileListener.onProgress(count,
                                Constant.OP_DOWNLOAD);
                        // publishProgress(new Long[]{count});
                    }
                }
                Log.d(TAG,"progress downloading write file ok mDestPath is "+mDestPath);
            }
            return "ok";
        } catch (IllegalStateException e) {
            mException = new KanboxException(e);
            Log.e(TAG,"progress downloading write file err IllegalStateException mDestPath is "+mDestPath);
            e.printStackTrace();
            return "error";
        } catch (IOException e) {
            mException = new KanboxException(e);
            Log.e(TAG,"progress downloading write file err IOException mDestPath is "+mDestPath);
            e.printStackTrace();
            return "error";
        }
    }

    public static DefaultHttpClient createHttpClient() {

        final HttpParams httpParams = createHttpParams();

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory
                .getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(),
                443));
        ClientConnectionManager cm = new ThreadSafeClientConnManager(
                httpParams, schemeRegistry);
        return new DefaultHttpClient(cm, httpParams);
    }

    private static HttpParams createHttpParams() {

        final HttpParams params = new BasicHttpParams();
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        HttpConnectionParams.setConnectionTimeout(params, 10 * 1000);
        HttpConnectionParams.setSoTimeout(params, 10 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);

        params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
        params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE,
                new ConnPerRouteBean(30));
        params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

        return params;
    }

    public static class KanboxHttp {

        public static HttpGet doGet(String url) {
            return doGet(url, null, null);
        }

        @SuppressWarnings("rawtypes")
        public static HttpGet doGet(String url, Map params) {
            return doGet(url, params, null);
        }

        public static HttpGet doGet(String url, Token token) {
            return doGet(url, null, token);
        }

        @SuppressWarnings("rawtypes")
        public static HttpGet doGet(String url, Map params, Token token) {
            if (params != null && params.size() > 0) {
                String paramStr = "";
                Iterator iter = params.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    Object key = entry.getKey();
                    Object val = entry.getValue();
                    paramStr += paramStr = "&" + key + "=" + val;
                }

                if (!paramStr.equals("")) {
                    paramStr = paramStr.replaceFirst("&", "?");
                    url += paramStr;
                }
            }
            /*URL mURL=null;
            URI uri = null;
            try {
                mURL = new URL(url);
                uri = new URI(mURL.getProtocol(), mURL.getHost(), mURL.getPath(), mURL.getQuery(), null);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            Log.e(TAG,"doGet ------------mURL is "+mURL+", uri is "+uri);*/

            HttpGet httpRequest = new HttpGet(url);
            if (token != null) {
                httpRequest.setHeader("Authorization",
                        "Bearer " + token.getAcceccToken());
            }
            return httpRequest;
        }

        @SuppressWarnings("rawtypes")
        public static HttpPost doPost(String url, Map params)
                throws UnsupportedEncodingException {
            String paramStr = "";

            if (params != null && params.size() > 0) {
                Iterator iter = params.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    Object key = entry.getKey();
                    Object val = entry.getValue();
                    paramStr += "&" + key + "=" + val;
                }

                if (!paramStr.equals("")) {
                    paramStr = paramStr.substring(1);
                }
            }
            return doPost(url, paramStr, null);
        }

        public static HttpPost doPost(String url, String params)
                throws UnsupportedEncodingException {
            return doPost(url, params, null);
        }

        public static HttpPost doPost(String url, String params, Token token)
                throws UnsupportedEncodingException {
            URL mURL=null;
            URI uri = null;
            try {
                mURL = new URL(url);
                uri = new URI(mURL.getProtocol(), mURL.getHost(), mURL.getPath(), mURL.getQuery(), null);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            //Log.d(TAG,"doPost ------------mURL is "+mURL+", uri is "+uri+",url is "+url);
            HttpPost httpRequest = new HttpPost(uri);
            httpRequest.setHeader("Content-Type",
                    "application/x-www-form-urlencoded");

            if (params != null && params.length() > 0) {
                httpRequest.setEntity(new StringEntity(params, HTTP.UTF_8));
            }

            if (token != null) {
                httpRequest.setHeader("Authorization",
                        "Bearer " + token.getAcceccToken());
            }
            return httpRequest;
        }

    }

}
